In [1]:
######## snakemake preamble start (automatically inserted, do not edit) ########
import sys; sys.path.extend(['/home/ckikawa/.conda/envs/seqneut-pipeline/lib/python3.11/site-packages', '/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/seqneut-pipeline', '/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024', '/home/ckikawa/.conda/envs/seqneut-pipeline/bin', '/home/ckikawa/.conda/envs/seqneut-pipeline/lib/python3.11', '/home/ckikawa/.conda/envs/seqneut-pipeline/lib/python3.11/lib-dynload', '/home/ckikawa/.local/lib/python3.11/site-packages', '/home/ckikawa/.conda/envs/seqneut-pipeline/lib/python3.11/site-packages', '/home/ckikawa/.cache/snakemake/snakemake/source-cache/runtime-cache/tmpy6xj203u/file/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/seqneut-pipeline/notebooks', '/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/seqneut-pipeline/notebooks']); import pickle; snakemake = pickle.loads(b'\x80\x04\x95\x87\xb0\x00\x00\x00\x00\x00\x00\x8c\x10snakemake.script\x94\x8c\tSnakemake\x94\x93\x94)\x81\x94}\x94(\x8c\x05input\x94\x8c\x0csnakemake.io\x94\x8c\nInputFiles\x94\x93\x94)\x81\x94(\x8c.results/barcode_counts/plate38_SCH_pool_40.csv\x94\x8c5results/barcode_counts/plate38_PennPreVax_pool_40.csv\x94\x8c6results/barcode_counts/plate38_PennPostVax_pool_40.csv\x94\x8c9results/barcode_counts/plate38_SCHPennPrePost_pool_40.csv\x94\x8c.results/barcode_counts/plate38_SCH_pool_80.csv\x94\x8c5results/barcode_counts/plate38_PennPreVax_pool_80.csv\x94\x8c6results/barcode_counts/plate38_PennPostVax_pool_80.csv\x94\x8c9results/barcode_counts/plate38_SCHPennPrePost_pool_80.csv\x94\x8c/results/barcode_counts/plate38_SCH_pool_160.csv\x94\x8c6results/barcode_counts/plate38_PennPreVax_pool_160.csv\x94\x8c7results/barcode_counts/plate38_PennPostVax_pool_160.csv\x94\x8c:results/barcode_counts/plate38_SCHPennPrePost_pool_160.csv\x94\x8c/results/barcode_counts/plate38_SCH_pool_320.csv\x94\x8c6results/barcode_counts/plate38_PennPreVax_pool_320.csv\x94\x8c7results/barcode_counts/plate38_PennPostVax_pool_320.csv\x94\x8c:results/barcode_counts/plate38_SCHPennPrePost_pool_320.csv\x94\x8c/results/barcode_counts/plate38_SCH_pool_640.csv\x94\x8c6results/barcode_counts/plate38_PennPreVax_pool_640.csv\x94\x8c7results/barcode_counts/plate38_PennPostVax_pool_640.csv\x94\x8c:results/barcode_counts/plate38_SCHPennPrePost_pool_640.csv\x94\x8c0results/barcode_counts/plate38_SCH_pool_1280.csv\x94\x8c7results/barcode_counts/plate38_PennPreVax_pool_1280.csv\x94\x8c8results/barcode_counts/plate38_PennPostVax_pool_1280.csv\x94\x8c;results/barcode_counts/plate38_SCHPennPrePost_pool_1280.csv\x94\x8c0results/barcode_counts/plate38_SCH_pool_2560.csv\x94\x8c7results/barcode_counts/plate38_PennPreVax_pool_2560.csv\x94\x8c8results/barcode_counts/plate38_PennPostVax_pool_2560.csv\x94\x8c;results/barcode_counts/plate38_SCHPennPrePost_pool_2560.csv\x94\x8c0results/barcode_counts/plate38_SCH_pool_5120.csv\x94\x8c7results/barcode_counts/plate38_PennPreVax_pool_5120.csv\x94\x8c8results/barcode_counts/plate38_PennPostVax_pool_5120.csv\x94\x8c;results/barcode_counts/plate38_SCHPennPrePost_pool_5120.csv\x94\x8c1results/barcode_counts/plate38_SCH_pool_10240.csv\x94\x8c8results/barcode_counts/plate38_PennPreVax_pool_10240.csv\x94\x8c9results/barcode_counts/plate38_PennPostVax_pool_10240.csv\x94\x8c<results/barcode_counts/plate38_SCHPennPrePost_pool_10240.csv\x94\x8c1results/barcode_counts/plate38_SCH_pool_20480.csv\x94\x8c8results/barcode_counts/plate38_PennPreVax_pool_20480.csv\x94\x8c9results/barcode_counts/plate38_PennPostVax_pool_20480.csv\x94\x8c<results/barcode_counts/plate38_SCHPennPrePost_pool_20480.csv\x94\x8c1results/barcode_counts/plate38_SCH_pool_40960.csv\x94\x8c8results/barcode_counts/plate38_PennPreVax_pool_40960.csv\x94\x8c9results/barcode_counts/plate38_PennPostVax_pool_40960.csv\x94\x8c<results/barcode_counts/plate38_SCHPennPrePost_pool_40960.csv\x94\x8c)results/barcode_counts/plate38_none-1.csv\x94\x8c)results/barcode_counts/plate38_none-2.csv\x94\x8c)results/barcode_counts/plate38_none-3.csv\x94\x8c)results/barcode_counts/plate38_none-4.csv\x94\x8c)results/barcode_counts/plate38_none-5.csv\x94\x8c)results/barcode_counts/plate38_none-6.csv\x94\x8c)results/barcode_counts/plate38_none-7.csv\x94\x8c)results/barcode_counts/plate38_none-8.csv\x94\x8c-results/barcode_fates/plate38_SCH_pool_40.csv\x94\x8c4results/barcode_fates/plate38_PennPreVax_pool_40.csv\x94\x8c5results/barcode_fates/plate38_PennPostVax_pool_40.csv\x94\x8c8results/barcode_fates/plate38_SCHPennPrePost_pool_40.csv\x94\x8c-results/barcode_fates/plate38_SCH_pool_80.csv\x94\x8c4results/barcode_fates/plate38_PennPreVax_pool_80.csv\x94\x8c5results/barcode_fates/plate38_PennPostVax_pool_80.csv\x94\x8c8results/barcode_fates/plate38_SCHPennPrePost_pool_80.csv\x94\x8c.results/barcode_fates/plate38_SCH_pool_160.csv\x94\x8c5results/barcode_fates/plate38_PennPreVax_pool_160.csv\x94\x8c6results/barcode_fates/plate38_PennPostVax_pool_160.csv\x94\x8c9results/barcode_fates/plate38_SCHPennPrePost_pool_160.csv\x94\x8c.results/barcode_fates/plate38_SCH_pool_320.csv\x94\x8c5results/barcode_fates/plate38_PennPreVax_pool_320.csv\x94\x8c6results/barcode_fates/plate38_PennPostVax_pool_320.csv\x94\x8c9results/barcode_fates/plate38_SCHPennPrePost_pool_320.csv\x94\x8c.results/barcode_fates/plate38_SCH_pool_640.csv\x94\x8c5results/barcode_fates/plate38_PennPreVax_pool_640.csv\x94\x8c6results/barcode_fates/plate38_PennPostVax_pool_640.csv\x94\x8c9results/barcode_fates/plate38_SCHPennPrePost_pool_640.csv\x94\x8c/results/barcode_fates/plate38_SCH_pool_1280.csv\x94\x8c6results/barcode_fates/plate38_PennPreVax_pool_1280.csv\x94\x8c7results/barcode_fates/plate38_PennPostVax_pool_1280.csv\x94\x8c:results/barcode_fates/plate38_SCHPennPrePost_pool_1280.csv\x94\x8c/results/barcode_fates/plate38_SCH_pool_2560.csv\x94\x8c6results/barcode_fates/plate38_PennPreVax_pool_2560.csv\x94\x8c7results/barcode_fates/plate38_PennPostVax_pool_2560.csv\x94\x8c:results/barcode_fates/plate38_SCHPennPrePost_pool_2560.csv\x94\x8c/results/barcode_fates/plate38_SCH_pool_5120.csv\x94\x8c6results/barcode_fates/plate38_PennPreVax_pool_5120.csv\x94\x8c7results/barcode_fates/plate38_PennPostVax_pool_5120.csv\x94\x8c:results/barcode_fates/plate38_SCHPennPrePost_pool_5120.csv\x94\x8c0results/barcode_fates/plate38_SCH_pool_10240.csv\x94\x8c7results/barcode_fates/plate38_PennPreVax_pool_10240.csv\x94\x8c8results/barcode_fates/plate38_PennPostVax_pool_10240.csv\x94\x8c;results/barcode_fates/plate38_SCHPennPrePost_pool_10240.csv\x94\x8c0results/barcode_fates/plate38_SCH_pool_20480.csv\x94\x8c7results/barcode_fates/plate38_PennPreVax_pool_20480.csv\x94\x8c8results/barcode_fates/plate38_PennPostVax_pool_20480.csv\x94\x8c;results/barcode_fates/plate38_SCHPennPrePost_pool_20480.csv\x94\x8c0results/barcode_fates/plate38_SCH_pool_40960.csv\x94\x8c7results/barcode_fates/plate38_PennPreVax_pool_40960.csv\x94\x8c8results/barcode_fates/plate38_PennPostVax_pool_40960.csv\x94\x8c;results/barcode_fates/plate38_SCHPennPrePost_pool_40960.csv\x94\x8c(results/barcode_fates/plate38_none-1.csv\x94\x8c(results/barcode_fates/plate38_none-2.csv\x94\x8c(results/barcode_fates/plate38_none-3.csv\x94\x8c(results/barcode_fates/plate38_none-4.csv\x94\x8c(results/barcode_fates/plate38_none-5.csv\x94\x8c(results/barcode_fates/plate38_none-6.csv\x94\x8c(results/barcode_fates/plate38_none-7.csv\x94\x8c(results/barcode_fates/plate38_none-8.csv\x94\x8c)data/viral_libraries/2023_H3N2_Kikawa.csv\x94\x8c3data/neut_standard_sets/loes2023_neut_standards.csv\x94e}\x94(\x8c\x06_names\x94}\x94(\x8c\ncount_csvs\x94K\x00K4\x86\x94\x8c\tfate_csvs\x94K4Kh\x86\x94\x8c\x11viral_library_csv\x94KhN\x86\x94\x8c\x15neut_standard_set_csv\x94KiN\x86\x94u\x8c\x12_allowed_overrides\x94]\x94(\x8c\x05index\x94\x8c\x04sort\x94eh\x81\x8c\tfunctools\x94\x8c\x07partial\x94\x93\x94h\x06\x8c\x19Namedlist._used_attribute\x94\x93\x94\x85\x94R\x94(h\x87)}\x94\x8c\x05_name\x94h\x81sNt\x94bh\x82h\x85h\x87\x85\x94R\x94(h\x87)}\x94h\x8bh\x82sNt\x94bhwh\x06\x8c\tNamedlist\x94\x93\x94)\x81\x94(h\nh\x0bh\x0ch\rh\x0eh\x0fh\x10h\x11h\x12h\x13h\x14h\x15h\x16h\x17h\x18h\x19h\x1ah\x1bh\x1ch\x1dh\x1eh\x1fh h!h"h#h$h%h&h\'h(h)h*h+h,h-h.h/h0h1h2h3h4h5h6h7h8h9h:h;h<h=e}\x94(hu}\x94h\x7f]\x94(h\x81h\x82eh\x81h\x85h\x87\x85\x94R\x94(h\x87)}\x94h\x8bh\x81sNt\x94bh\x82h\x85h\x87\x85\x94R\x94(h\x87)}\x94h\x8bh\x82sNt\x94bubhyh\x92)\x81\x94(h>h?h@hAhBhChDhEhFhGhHhIhJhKhLhMhNhOhPhQhRhShThUhVhWhXhYhZh[h\\h]h^h_h`hahbhchdhehfhghhhihjhkhlhmhnhohphqe}\x94(hu}\x94h\x7f]\x94(h\x81h\x82eh\x81h\x85h\x87\x85\x94R\x94(h\x87)}\x94h\x8bh\x81sNt\x94bh\x82h\x85h\x87\x85\x94R\x94(h\x87)}\x94h\x8bh\x82sNt\x94bubh{hrh}hsub\x8c\x06output\x94h\x06\x8c\x0bOutputFiles\x94\x93\x94)\x81\x94(\x8c#results/plates/plate38/qc_drops.yml\x94\x8c+results/plates/plate38/frac_infectivity.csv\x94\x8c$results/plates/plate38/curvefits.csv\x94\x8c\'results/plates/plate38/curvefits.pickle\x94e}\x94(hu}\x94(\x8c\x08qc_drops\x94K\x00N\x86\x94\x8c\x14frac_infectivity_csv\x94K\x01N\x86\x94\x8c\x08fits_csv\x94K\x02N\x86\x94\x8c\x0bfits_pickle\x94K\x03N\x86\x94uh\x7f]\x94(h\x81h\x82eh\x81h\x85h\x87\x85\x94R\x94(h\x87)}\x94h\x8bh\x81sNt\x94bh\x82h\x85h\x87\x85\x94R\x94(h\x87)}\x94h\x8bh\x82sNt\x94bh\xb5h\xafh\xb7h\xb0h\xb9h\xb1h\xbbh\xb2ub\x8c\x06params\x94h\x06\x8c\x06Params\x94\x93\x94)\x81\x94(]\x94(\x8c\x13plate38_SCH_pool_40\x94\x8c\x1aplate38_PennPreVax_pool_40\x94\x8c\x1bplate38_PennPostVax_pool_40\x94\x8c\x1eplate38_SCHPennPrePost_pool_40\x94\x8c\x13plate38_SCH_pool_80\x94\x8c\x1aplate38_PennPreVax_pool_80\x94\x8c\x1bplate38_PennPostVax_pool_80\x94\x8c\x1eplate38_SCHPennPrePost_pool_80\x94\x8c\x14plate38_SCH_pool_160\x94\x8c\x1bplate38_PennPreVax_pool_160\x94\x8c\x1cplate38_PennPostVax_pool_160\x94\x8c\x1fplate38_SCHPennPrePost_pool_160\x94\x8c\x14plate38_SCH_pool_320\x94\x8c\x1bplate38_PennPreVax_pool_320\x94\x8c\x1cplate38_PennPostVax_pool_320\x94\x8c\x1fplate38_SCHPennPrePost_pool_320\x94\x8c\x14plate38_SCH_pool_640\x94\x8c\x1bplate38_PennPreVax_pool_640\x94\x8c\x1cplate38_PennPostVax_pool_640\x94\x8c\x1fplate38_SCHPennPrePost_pool_640\x94\x8c\x15plate38_SCH_pool_1280\x94\x8c\x1cplate38_PennPreVax_pool_1280\x94\x8c\x1dplate38_PennPostVax_pool_1280\x94\x8c plate38_SCHPennPrePost_pool_1280\x94\x8c\x15plate38_SCH_pool_2560\x94\x8c\x1cplate38_PennPreVax_pool_2560\x94\x8c\x1dplate38_PennPostVax_pool_2560\x94\x8c plate38_SCHPennPrePost_pool_2560\x94\x8c\x15plate38_SCH_pool_5120\x94\x8c\x1cplate38_PennPreVax_pool_5120\x94\x8c\x1dplate38_PennPostVax_pool_5120\x94\x8c plate38_SCHPennPrePost_pool_5120\x94\x8c\x16plate38_SCH_pool_10240\x94\x8c\x1dplate38_PennPreVax_pool_10240\x94\x8c\x1eplate38_PennPostVax_pool_10240\x94\x8c!plate38_SCHPennPrePost_pool_10240\x94\x8c\x16plate38_SCH_pool_20480\x94\x8c\x1dplate38_PennPreVax_pool_20480\x94\x8c\x1eplate38_PennPostVax_pool_20480\x94\x8c!plate38_SCHPennPrePost_pool_20480\x94\x8c\x16plate38_SCH_pool_40960\x94\x8c\x1dplate38_PennPreVax_pool_40960\x94\x8c\x1eplate38_PennPostVax_pool_40960\x94\x8c!plate38_SCHPennPrePost_pool_40960\x94\x8c\x0eplate38_none-1\x94\x8c\x0eplate38_none-2\x94\x8c\x0eplate38_none-3\x94\x8c\x0eplate38_none-4\x94\x8c\x0eplate38_none-5\x94\x8c\x0eplate38_none-6\x94\x8c\x0eplate38_none-7\x94\x8c\x0eplate38_none-8\x94e}\x94(\x8c\x05group\x94\x8c\nPooledSera\x94\x8c\x04date\x94\x8c\n2024-09-24\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-09-24_plate_mapping_file38.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(\x8c\x1bavg_barcode_counts_per_well\x94M\xf4\x01\x8c\x1fmin_neut_standard_frac_per_well\x94G?tz\xe1G\xae\x14{\x8c"no_serum_per_viral_barcode_filters\x94}\x94(\x8c\x08min_frac\x94G?\x1a6\xe2\xeb\x1cC-\x8c\x0fmax_fold_change\x94K\x04\x8c\tmax_wells\x94K\x02u\x8c!per_neut_standard_barcode_filters\x94}\x94(\x8c\x08min_frac\x94G?tz\xe1G\xae\x14{\x8c\x0fmax_fold_change\x94K\x04\x8c\tmax_wells\x94K\x02u\x8c min_neut_standard_count_per_well\x94M\xe8\x03\x8c)min_no_serum_count_per_viral_barcode_well\x94Kd\x8c+max_frac_infectivity_per_viral_barcode_well\x94K\x03\x8c)min_dilutions_per_barcode_serum_replicate\x94K\x06u\x8c\x0fcurvefit_params\x94}\x94(\x8c\x18frac_infectivity_ceiling\x94K\x01\x8c\x06fixtop\x94]\x94(G?\xe3333333K\x01e\x8c\tfixbottom\x94K\x00\x8c\x08fixslope\x94]\x94(G?\xe9\x99\x99\x99\x99\x99\x9aK\neu\x8c\x0bcurvefit_qc\x94}\x94(\x8c\x1dmax_frac_infectivity_at_least\x94G\x00\x00\x00\x00\x00\x00\x00\x00\x8c\x0fgoodness_of_fit\x94}\x94(\x8c\x06min_R2\x94G?\xe0\x00\x00\x00\x00\x00\x00\x8c\x08max_RMSD\x94G?\xc3333333u\x8c#serum_replicates_ignore_curvefit_qc\x94]\x94\x8c+barcode_serum_replicates_ignore_curvefit_qc\x94]\x94u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\x08upstream\x94\x8c\x1cCCTACAATGTCGGATTTGTATTTAATAG\x94\x8c\ndownstream\x94\x8c\x00\x94\x8c\x04minq\x94K\x14\x8c\x11upstream_mismatch\x94K\x04\x8c\x0ebc_orientation\x94\x8c\x02R2\x94\x8c\tupstream2\x94\x8c\x06ATCGAT\x94\x8c\x12upstream2_mismatch\x94K\x01u\x8c\x07samples\x94}\x94(\x8c\x04well\x94}\x94(K\x00\x8c\x02A1\x94K\x01\x8c\x02B1\x94K\x02\x8c\x02C1\x94K\x03\x8c\x02D1\x94K\x04\x8c\x02A2\x94K\x05\x8c\x02B2\x94K\x06\x8c\x02C2\x94K\x07\x8c\x02D2\x94K\x08\x8c\x02A3\x94K\t\x8c\x02B3\x94K\n\x8c\x02C3\x94K\x0b\x8c\x02D3\x94K\x0c\x8c\x02A4\x94K\r\x8c\x02B4\x94K\x0e\x8c\x02C4\x94K\x0f\x8c\x02D4\x94K\x10\x8c\x02A5\x94K\x11\x8c\x02B5\x94K\x12\x8c\x02C5\x94K\x13\x8c\x02D5\x94K\x14\x8c\x02A6\x94K\x15\x8c\x02B6\x94K\x16\x8c\x02C6\x94K\x17\x8c\x02D6\x94K\x18\x8c\x02A7\x94K\x19\x8c\x02B7\x94K\x1a\x8c\x02C7\x94K\x1b\x8c\x02D7\x94K\x1c\x8c\x02A8\x94K\x1d\x8c\x02B8\x94K\x1e\x8c\x02C8\x94K\x1f\x8c\x02D8\x94K \x8c\x02A9\x94K!\x8c\x02B9\x94K"\x8c\x02C9\x94K#\x8c\x02D9\x94K$\x8c\x03A10\x94K%\x8c\x03B10\x94K&\x8c\x03C10\x94K\'\x8c\x03D10\x94K(\x8c\x03A11\x94K)\x8c\x03B11\x94K*\x8c\x03C11\x94K+\x8c\x03D11\x94K,\x8c\x03A12\x94K-\x8c\x03B12\x94K.\x8c\x03C12\x94K/\x8c\x03D12\x94K0\x8c\x03E12\x94K1\x8c\x03F12\x94K2\x8c\x03G12\x94K3\x8c\x03H12\x94u\x8c\x05serum\x94}\x94(K\x00\x8c\x08SCH_pool\x94K\x01\x8c\x0fPennPreVax_pool\x94K\x02\x8c\x10PennPostVax_pool\x94K\x03\x8c\x13SCHPennPrePost_pool\x94K\x04jx\x01\x00\x00K\x05jy\x01\x00\x00K\x06jz\x01\x00\x00K\x07j{\x01\x00\x00K\x08jx\x01\x00\x00K\tjy\x01\x00\x00K\njz\x01\x00\x00K\x0bj{\x01\x00\x00K\x0cjx\x01\x00\x00K\rjy\x01\x00\x00K\x0ejz\x01\x00\x00K\x0fj{\x01\x00\x00K\x10jx\x01\x00\x00K\x11jy\x01\x00\x00K\x12jz\x01\x00\x00K\x13j{\x01\x00\x00K\x14jx\x01\x00\x00K\x15jy\x01\x00\x00K\x16jz\x01\x00\x00K\x17j{\x01\x00\x00K\x18jx\x01\x00\x00K\x19jy\x01\x00\x00K\x1ajz\x01\x00\x00K\x1bj{\x01\x00\x00K\x1cjx\x01\x00\x00K\x1djy\x01\x00\x00K\x1ejz\x01\x00\x00K\x1fj{\x01\x00\x00K jx\x01\x00\x00K!jy\x01\x00\x00K"jz\x01\x00\x00K#j{\x01\x00\x00K$jx\x01\x00\x00K%jy\x01\x00\x00K&jz\x01\x00\x00K\'j{\x01\x00\x00K(jx\x01\x00\x00K)jy\x01\x00\x00K*jz\x01\x00\x00K+j{\x01\x00\x00K,\x8c\x04none\x94K-j|\x01\x00\x00K.j|\x01\x00\x00K/j|\x01\x00\x00K0j|\x01\x00\x00K1j|\x01\x00\x00K2j|\x01\x00\x00K3j|\x01\x00\x00u\x8c\x0fdilution_factor\x94}\x94(K\x00K(K\x01K(K\x02K(K\x03K(K\x04KPK\x05KPK\x06KPK\x07KPK\x08K\xa0K\tK\xa0K\nK\xa0K\x0bK\xa0K\x0cM@\x01K\rM@\x01K\x0eM@\x01K\x0fM@\x01K\x10M\x80\x02K\x11M\x80\x02K\x12M\x80\x02K\x13M\x80\x02K\x14M\x00\x05K\x15M\x00\x05K\x16M\x00\x05K\x17M\x00\x05K\x18M\x00\nK\x19M\x00\nK\x1aM\x00\nK\x1bM\x00\nK\x1cM\x00\x14K\x1dM\x00\x14K\x1eM\x00\x14K\x1fM\x00\x14K M\x00(K!M\x00(K"M\x00(K#M\x00(K$M\x00PK%M\x00PK&M\x00PK\'M\x00PK(M\x00\xa0K)M\x00\xa0K*M\x00\xa0K+M\x00\xa0K,NK-NK.NK/NK0NK1NK2NK3Nu\x8c\treplicate\x94}\x94(K\x00K\x01K\x01K\x01K\x02K\x01K\x03K\x01K\x04K\x01K\x05K\x01K\x06K\x01K\x07K\x01K\x08K\x01K\tK\x01K\nK\x01K\x0bK\x01K\x0cK\x01K\rK\x01K\x0eK\x01K\x0fK\x01K\x10K\x01K\x11K\x01K\x12K\x01K\x13K\x01K\x14K\x01K\x15K\x01K\x16K\x01K\x17K\x01K\x18K\x01K\x19K\x01K\x1aK\x01K\x1bK\x01K\x1cK\x01K\x1dK\x01K\x1eK\x01K\x1fK\x01K K\x01K!K\x01K"K\x01K#K\x01K$K\x01K%K\x01K&K\x01K\'K\x01K(K\x01K)K\x01K*K\x01K+K\x01K,K\x01K-K\x02K.K\x03K/K\x04K0K\x05K1K\x06K2K\x07K3K\x08u\x8c\x05fastq\x94}\x94(K\x00\x8cx/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_1_S97_R1_001.fastq.gz\x94K\x01\x8cx/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_2_S98_R1_001.fastq.gz\x94K\x02\x8cx/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_3_S99_R1_001.fastq.gz\x94K\x03\x8cy/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_4_S100_R1_001.fastq.gz\x94K\x04\x8cy/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_9_S105_R1_001.fastq.gz\x94K\x05\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_10_S106_R1_001.fastq.gz\x94K\x06\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_11_S107_R1_001.fastq.gz\x94K\x07\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_12_S108_R1_001.fastq.gz\x94K\x08\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_17_S113_R1_001.fastq.gz\x94K\t\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_18_S114_R1_001.fastq.gz\x94K\n\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_19_S115_R1_001.fastq.gz\x94K\x0b\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_20_S116_R1_001.fastq.gz\x94K\x0c\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_25_S121_R1_001.fastq.gz\x94K\r\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_26_S122_R1_001.fastq.gz\x94K\x0e\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_27_S123_R1_001.fastq.gz\x94K\x0f\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_28_S124_R1_001.fastq.gz\x94K\x10\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_33_S129_R1_001.fastq.gz\x94K\x11\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_34_S130_R1_001.fastq.gz\x94K\x12\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_35_S131_R1_001.fastq.gz\x94K\x13\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_36_S132_R1_001.fastq.gz\x94K\x14\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_41_S137_R1_001.fastq.gz\x94K\x15\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_42_S138_R1_001.fastq.gz\x94K\x16\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_43_S139_R1_001.fastq.gz\x94K\x17\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_44_S140_R1_001.fastq.gz\x94K\x18\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_49_S145_R1_001.fastq.gz\x94K\x19\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_50_S146_R1_001.fastq.gz\x94K\x1a\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_51_S147_R1_001.fastq.gz\x94K\x1b\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_52_S148_R1_001.fastq.gz\x94K\x1c\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_57_S153_R1_001.fastq.gz\x94K\x1d\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_58_S154_R1_001.fastq.gz\x94K\x1e\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_59_S155_R1_001.fastq.gz\x94K\x1f\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_60_S156_R1_001.fastq.gz\x94K \x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_65_S161_R1_001.fastq.gz\x94K!\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_66_S162_R1_001.fastq.gz\x94K"\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_67_S163_R1_001.fastq.gz\x94K#\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_68_S164_R1_001.fastq.gz\x94K$\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_73_S169_R1_001.fastq.gz\x94K%\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_74_S170_R1_001.fastq.gz\x94K&\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_75_S171_R1_001.fastq.gz\x94K\'\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_76_S172_R1_001.fastq.gz\x94K(\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_81_S177_R1_001.fastq.gz\x94K)\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_82_S178_R1_001.fastq.gz\x94K*\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_83_S179_R1_001.fastq.gz\x94K+\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_84_S180_R1_001.fastq.gz\x94K,\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_89_S185_R1_001.fastq.gz\x94K-\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_90_S186_R1_001.fastq.gz\x94K.\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_91_S187_R1_001.fastq.gz\x94K/\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_92_S188_R1_001.fastq.gz\x94K0\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_93_S189_R1_001.fastq.gz\x94K1\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_94_S190_R1_001.fastq.gz\x94K2\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_95_S191_R1_001.fastq.gz\x94K3\x8cz/fh/fast/bloom_j/SR/ngs/illumina/aloes/240919_VH01189_348_AAFT2LVM5/Unaligned/Project_aloes/PlateB_96_S192_R1_001.fastq.gz\x94u\x8c\x0fserum_replicate\x94}\x94(K\x00jx\x01\x00\x00K\x01jy\x01\x00\x00K\x02jz\x01\x00\x00K\x03j{\x01\x00\x00K\x04jx\x01\x00\x00K\x05jy\x01\x00\x00K\x06jz\x01\x00\x00K\x07j{\x01\x00\x00K\x08jx\x01\x00\x00K\tjy\x01\x00\x00K\njz\x01\x00\x00K\x0bj{\x01\x00\x00K\x0cjx\x01\x00\x00K\rjy\x01\x00\x00K\x0ejz\x01\x00\x00K\x0fj{\x01\x00\x00K\x10jx\x01\x00\x00K\x11jy\x01\x00\x00K\x12jz\x01\x00\x00K\x13j{\x01\x00\x00K\x14jx\x01\x00\x00K\x15jy\x01\x00\x00K\x16jz\x01\x00\x00K\x17j{\x01\x00\x00K\x18jx\x01\x00\x00K\x19jy\x01\x00\x00K\x1ajz\x01\x00\x00K\x1bj{\x01\x00\x00K\x1cjx\x01\x00\x00K\x1djy\x01\x00\x00K\x1ejz\x01\x00\x00K\x1fj{\x01\x00\x00K jx\x01\x00\x00K!jy\x01\x00\x00K"jz\x01\x00\x00K#j{\x01\x00\x00K$jx\x01\x00\x00K%jy\x01\x00\x00K&jz\x01\x00\x00K\'j{\x01\x00\x00K(jx\x01\x00\x00K)jy\x01\x00\x00K*jz\x01\x00\x00K+j{\x01\x00\x00K,\x8c\x06none-1\x94K-\x8c\x06none-2\x94K.\x8c\x06none-3\x94K/\x8c\x06none-4\x94K0\x8c\x06none-5\x94K1\x8c\x06none-6\x94K2\x8c\x06none-7\x94K3\x8c\x06none-8\x94u\x8c\x0esample_noplate\x94}\x94(K\x00\x8c\x0bSCH_pool_40\x94K\x01\x8c\x12PennPreVax_pool_40\x94K\x02\x8c\x13PennPostVax_pool_40\x94K\x03\x8c\x16SCHPennPrePost_pool_40\x94K\x04\x8c\x0bSCH_pool_80\x94K\x05\x8c\x12PennPreVax_pool_80\x94K\x06\x8c\x13PennPostVax_pool_80\x94K\x07\x8c\x16SCHPennPrePost_pool_80\x94K\x08\x8c\x0cSCH_pool_160\x94K\t\x8c\x13PennPreVax_pool_160\x94K\n\x8c\x14PennPostVax_pool_160\x94K\x0b\x8c\x17SCHPennPrePost_pool_160\x94K\x0c\x8c\x0cSCH_pool_320\x94K\r\x8c\x13PennPreVax_pool_320\x94K\x0e\x8c\x14PennPostVax_pool_320\x94K\x0f\x8c\x17SCHPennPrePost_pool_320\x94K\x10\x8c\x0cSCH_pool_640\x94K\x11\x8c\x13PennPreVax_pool_640\x94K\x12\x8c\x14PennPostVax_pool_640\x94K\x13\x8c\x17SCHPennPrePost_pool_640\x94K\x14\x8c\rSCH_pool_1280\x94K\x15\x8c\x14PennPreVax_pool_1280\x94K\x16\x8c\x15PennPostVax_pool_1280\x94K\x17\x8c\x18SCHPennPrePost_pool_1280\x94K\x18\x8c\rSCH_pool_2560\x94K\x19\x8c\x14PennPreVax_pool_2560\x94K\x1a\x8c\x15PennPostVax_pool_2560\x94K\x1b\x8c\x18SCHPennPrePost_pool_2560\x94K\x1c\x8c\rSCH_pool_5120\x94K\x1d\x8c\x14PennPreVax_pool_5120\x94K\x1e\x8c\x15PennPostVax_pool_5120\x94K\x1f\x8c\x18SCHPennPrePost_pool_5120\x94K \x8c\x0eSCH_pool_10240\x94K!\x8c\x15PennPreVax_pool_10240\x94K"\x8c\x16PennPostVax_pool_10240\x94K#\x8c\x19SCHPennPrePost_pool_10240\x94K$\x8c\x0eSCH_pool_20480\x94K%\x8c\x15PennPreVax_pool_20480\x94K&\x8c\x16PennPostVax_pool_20480\x94K\'\x8c\x19SCHPennPrePost_pool_20480\x94K(\x8c\x0eSCH_pool_40960\x94K)\x8c\x15PennPreVax_pool_40960\x94K*\x8c\x16PennPostVax_pool_40960\x94K+\x8c\x19SCHPennPrePost_pool_40960\x94K,j\xb9\x01\x00\x00K-j\xba\x01\x00\x00K.j\xbb\x01\x00\x00K/j\xbc\x01\x00\x00K0j\xbd\x01\x00\x00K1j\xbe\x01\x00\x00K2j\xbf\x01\x00\x00K3j\xc0\x01\x00\x00u\x8c\x06sample\x94}\x94(K\x00h\xcbK\x01h\xccK\x02h\xcdK\x03h\xceK\x04h\xcfK\x05h\xd0K\x06h\xd1K\x07h\xd2K\x08h\xd3K\th\xd4K\nh\xd5K\x0bh\xd6K\x0ch\xd7K\rh\xd8K\x0eh\xd9K\x0fh\xdaK\x10h\xdbK\x11h\xdcK\x12h\xddK\x13h\xdeK\x14h\xdfK\x15h\xe0K\x16h\xe1K\x17h\xe2K\x18h\xe3K\x19h\xe4K\x1ah\xe5K\x1bh\xe6K\x1ch\xe7K\x1dh\xe8K\x1eh\xe9K\x1fh\xeaK h\xebK!h\xecK"h\xedK#h\xeeK$h\xefK%h\xf0K&h\xf1K\'h\xf2K(h\xf3K)h\xf4K*h\xf5K+h\xf6K,h\xf7K-h\xf8K.h\xf9K/h\xfaK0h\xfbK1h\xfcK2h\xfdK3h\xfeu\x8c\x05plate\x94}\x94(K\x00\x8c\x07plate38\x94K\x01j\xf3\x01\x00\x00K\x02j\xf3\x01\x00\x00K\x03j\xf3\x01\x00\x00K\x04j\xf3\x01\x00\x00K\x05j\xf3\x01\x00\x00K\x06j\xf3\x01\x00\x00K\x07j\xf3\x01\x00\x00K\x08j\xf3\x01\x00\x00K\tj\xf3\x01\x00\x00K\nj\xf3\x01\x00\x00K\x0bj\xf3\x01\x00\x00K\x0cj\xf3\x01\x00\x00K\rj\xf3\x01\x00\x00K\x0ej\xf3\x01\x00\x00K\x0fj\xf3\x01\x00\x00K\x10j\xf3\x01\x00\x00K\x11j\xf3\x01\x00\x00K\x12j\xf3\x01\x00\x00K\x13j\xf3\x01\x00\x00K\x14j\xf3\x01\x00\x00K\x15j\xf3\x01\x00\x00K\x16j\xf3\x01\x00\x00K\x17j\xf3\x01\x00\x00K\x18j\xf3\x01\x00\x00K\x19j\xf3\x01\x00\x00K\x1aj\xf3\x01\x00\x00K\x1bj\xf3\x01\x00\x00K\x1cj\xf3\x01\x00\x00K\x1dj\xf3\x01\x00\x00K\x1ej\xf3\x01\x00\x00K\x1fj\xf3\x01\x00\x00K j\xf3\x01\x00\x00K!j\xf3\x01\x00\x00K"j\xf3\x01\x00\x00K#j\xf3\x01\x00\x00K$j\xf3\x01\x00\x00K%j\xf3\x01\x00\x00K&j\xf3\x01\x00\x00K\'j\xf3\x01\x00\x00K(j\xf3\x01\x00\x00K)j\xf3\x01\x00\x00K*j\xf3\x01\x00\x00K+j\xf3\x01\x00\x00K,j\xf3\x01\x00\x00K-j\xf3\x01\x00\x00K.j\xf3\x01\x00\x00K/j\xf3\x01\x00\x00K0j\xf3\x01\x00\x00K1j\xf3\x01\x00\x00K2j\xf3\x01\x00\x00K3j\xf3\x01\x00\x00u\x8c\x0fplate_replicate\x94}\x94(K\x00j\xf3\x01\x00\x00K\x01j\xf3\x01\x00\x00K\x02j\xf3\x01\x00\x00K\x03j\xf3\x01\x00\x00K\x04j\xf3\x01\x00\x00K\x05j\xf3\x01\x00\x00K\x06j\xf3\x01\x00\x00K\x07j\xf3\x01\x00\x00K\x08j\xf3\x01\x00\x00K\tj\xf3\x01\x00\x00K\nj\xf3\x01\x00\x00K\x0bj\xf3\x01\x00\x00K\x0cj\xf3\x01\x00\x00K\rj\xf3\x01\x00\x00K\x0ej\xf3\x01\x00\x00K\x0fj\xf3\x01\x00\x00K\x10j\xf3\x01\x00\x00K\x11j\xf3\x01\x00\x00K\x12j\xf3\x01\x00\x00K\x13j\xf3\x01\x00\x00K\x14j\xf3\x01\x00\x00K\x15j\xf3\x01\x00\x00K\x16j\xf3\x01\x00\x00K\x17j\xf3\x01\x00\x00K\x18j\xf3\x01\x00\x00K\x19j\xf3\x01\x00\x00K\x1aj\xf3\x01\x00\x00K\x1bj\xf3\x01\x00\x00K\x1cj\xf3\x01\x00\x00K\x1dj\xf3\x01\x00\x00K\x1ej\xf3\x01\x00\x00K\x1fj\xf3\x01\x00\x00K j\xf3\x01\x00\x00K!j\xf3\x01\x00\x00K"j\xf3\x01\x00\x00K#j\xf3\x01\x00\x00K$j\xf3\x01\x00\x00K%j\xf3\x01\x00\x00K&j\xf3\x01\x00\x00K\'j\xf3\x01\x00\x00K(j\xf3\x01\x00\x00K)j\xf3\x01\x00\x00K*j\xf3\x01\x00\x00K+j\xf3\x01\x00\x00K,\x8c\tplate38-1\x94K-\x8c\tplate38-2\x94K.\x8c\tplate38-3\x94K/\x8c\tplate38-4\x94K0\x8c\tplate38-5\x94K1\x8c\tplate38-6\x94K2\x8c\tplate38-7\x94K3\x8c\tplate38-8\x94uuue}\x94(hu}\x94(j>\x01\x00\x00K\x00N\x86\x94\x8c\x0cplate_params\x94K\x01N\x86\x94uh\x7f]\x94(h\x81h\x82eh\x81h\x85h\x87\x85\x94R\x94(h\x87)}\x94h\x8bh\x81sNt\x94bh\x82h\x85h\x87\x85\x94R\x94(h\x87)}\x94h\x8bh\x82sNt\x94bj>\x01\x00\x00h\xcaj\x01\x02\x00\x00h\xffub\x8c\twildcards\x94h\x06\x8c\tWildcards\x94\x93\x94)\x81\x94\x8c\x07plate38\x94a}\x94(hu}\x94\x8c\x05plate\x94K\x00N\x86\x94sh\x7f]\x94(h\x81h\x82eh\x81h\x85h\x87\x85\x94R\x94(h\x87)}\x94h\x8bh\x81sNt\x94bh\x82h\x85h\x87\x85\x94R\x94(h\x87)}\x94h\x8bh\x82sNt\x94bj\xf1\x01\x00\x00j\x10\x02\x00\x00ub\x8c\x07threads\x94K\x01\x8c\tresources\x94h\x06\x8c\tResources\x94\x93\x94)\x81\x94(K\x01K\x01\x8c\x15/loc/scratch/64245082\x94e}\x94(hu}\x94(\x8c\x06_cores\x94K\x00N\x86\x94\x8c\x06_nodes\x94K\x01N\x86\x94\x8c\x06tmpdir\x94K\x02N\x86\x94uh\x7f]\x94(h\x81h\x82eh\x81h\x85h\x87\x85\x94R\x94(h\x87)}\x94h\x8bh\x81sNt\x94bh\x82h\x85h\x87\x85\x94R\x94(h\x87)}\x94h\x8bh\x82sNt\x94bj&\x02\x00\x00K\x01j(\x02\x00\x00K\x01j*\x02\x00\x00j#\x02\x00\x00ub\x8c\x03log\x94h\x06\x8c\x03Log\x94\x93\x94)\x81\x94\x8c,results/plates/plate38/process_plate38.ipynb\x94a}\x94(hu}\x94\x8c\x08notebook\x94K\x00N\x86\x94sh\x7f]\x94(h\x81h\x82eh\x81h\x85h\x87\x85\x94R\x94(h\x87)}\x94h\x8bh\x81sNt\x94bh\x82h\x85h\x87\x85\x94R\x94(h\x87)}\x94h\x8bh\x82sNt\x94bj<\x02\x00\x00j9\x02\x00\x00ub\x8c\x06config\x94}\x94(\x8c\x10seqneut-pipeline\x94\x8c\x10seqneut-pipeline\x94\x8c\x04docs\x94\x8c\x04docs\x94\x8c\x0bdescription\x94X\n\x01\x00\x00# Sequencing-based neutralization assays of 2023-2024 human serum samples versus H3N2 influenza libraries\n\nThe numerical data and computer code are at [https://github.com/jbloomlab/flu_seqneut_H3N2_2023-2024](https://github.com/jbloomlab/flu_seqneut_H3N2_2023-2024)\n\x94\x8c\x0fviral_libraries\x94}\x94(\x8c\x0cH3N2_library\x94\x8c)data/viral_libraries/2023_H3N2_Kikawa.csv\x94\x8c\x0cH1N1_library\x94\x8c-data/viral_libraries/pdmH1N1_lib2023_loes.csv\x94u\x8c\x17viral_strain_plot_order\x94\x8c)data/H3N2library_2023-2024_allStrains.csv\x94\x8c\x12neut_standard_sets\x94}\x94\x8c\x08loes2023\x94\x8c3data/neut_standard_sets/loes2023_neut_standards.csv\x94s\x8c\x1eillumina_barcode_parser_params\x94}\x94(j3\x01\x00\x00j4\x01\x00\x00j5\x01\x00\x00j6\x01\x00\x00j7\x01\x00\x00K\x14j8\x01\x00\x00K\x04j9\x01\x00\x00j:\x01\x00\x00u\x8c#default_process_plate_qc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c%default_process_plate_curvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00]\x94(G?\xe3333333K\x01ej#\x01\x00\x00K\x00j$\x01\x00\x00]\x94(G?\xe9\x99\x99\x99\x99\x99\x9aK\neu\x8c!default_process_plate_curvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00]\x94j/\x01\x00\x00]\x94u\x8c\x16default_serum_titer_as\x94\x8c\x08midpoint\x94\x8c\x1bdefault_serum_qc_thresholds\x94}\x94(\x8c\x0emin_replicates\x94K\x02\x8c\x1bmax_fold_change_from_median\x94K\x06\x8c\x11viruses_ignore_qc\x94]\x94u\x8c\x16sera_override_defaults\x94}\x94\x8c\x06plates\x94}\x94(\x8c\x06plate1\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94\x8c\x08datetime\x94\x8c\x04date\x94\x93\x94C\x04\x07\xe8\x01\x19\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c.data/plates/2024-01-22_plate_mapping_file2.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00uu\x8c\x06plate2\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x01\x19\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c.data/plates/2024-01-22_plate_mapping_file1.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00uu\x8c\x06plate3\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x01\x19\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c.data/plates/2024-01-22_plate_mapping_file3.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\x18barcode_serum_replicates\x94]\x94(]\x94(\x8c\x10AATGACAGCTGTCTAG\x94\x8c\x12A230212d0_r64_rep1\x94e]\x94(\x8c\x10ATAGAAAATTATCCGC\x94\x8c\x12A230212d0_r64_rep1\x94ees\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00uu\x8c\x06plate4\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x02\x07\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c.data/plates/2024-02-07_plate_mapping_file7.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00uu\x8c\x06plate5\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x02\x07\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c.data/plates/2024-02-07_plate_mapping_file4.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00uu\x8c\x06plate6\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x02\x07\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c.data/plates/2024-02-07_plate_mapping_file5.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00uu\x8c\x06plate7\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x02\x07\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c.data/plates/2024-02-07_plate_mapping_file6.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00uu\x8c\x0eplate8_r32_50k\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x03\x04\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-03-04_plate_mapping_file10.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00uu\x8c\x0eplate9_r64_50k\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x03\x04\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-03-04_plate_mapping_file12.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00uu\x8c\x10plate10_r128_50k\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x03\x04\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c.data/plates/2024-03-04_plate_mapping_file8.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00uu\x8c\x0fplate11_r32_75k\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x03\x04\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-03-04_plate_mapping_file11.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00uu\x8c\x0fplate12_r64_75k\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x03\x04\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-03-04_plate_mapping_file13.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00uu\x8c\x10plate13_r128_75k\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x03\x04\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c.data/plates/2024-03-04_plate_mapping_file9.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00uu\x8c\x07plate14\x94}\x94(\x8c\x05group\x94\x8c\x0eplatesToRepeat\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x03\x13\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-03-19_plate_mapping_file14.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rbarcode_wells\x94]\x94(]\x94(\x8c\x10AAGTATTGCTACACAT\x94\x8c\x02H3\x94e]\x94(\x8c\x10CCTATAAGGCCTTACG\x94\x8c\x02H3\x94ees\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00uu\x8c\x07plate15\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x03\x1c\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-03-28_plate_mapping_file15.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00uu\x8c\x07plate16\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x04\t\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-04-09_plate_mapping_file16.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00uu\x8c\x07plate17\x94}\x94(\x8c\x05group\x94\x8c\x03SCH\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x04\x0b\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-04-11_plate_mapping_file17.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\x05wells\x94]\x94\x8c\x02A9\x94as\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00uu\x8c\x07plate18\x94}\x94(\x8c\x05group\x94\x8c\x03SCH\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x04\x0b\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-04-11_plate_mapping_file18.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00uu\x8c\x0cplate19_100k\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x04\x10\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-04-23_plate_mapping_file21.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00uu\x8c\x0cplate20_150k\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x04\x10\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-04-23_plate_mapping_file22.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00uu\x8c\x0cplate21_200k\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x04\x10\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-04-23_plate_mapping_file23.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00uu\x8c\x07plate22\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x04\x12\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-04-18_plate_mapping_file19.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06TGACGC\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate23\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x04\x12\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-04-18_plate_mapping_file20.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06CAGTTG\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate24\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x05\x02\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-05-02_plate_mapping_file24.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00uu\x8c\x07plate25\x94}\x94(\x8c\x05group\x94\x8c\x03SCH\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x05\x14\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-05-20_plate_mapping_file27.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06TGACGC\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate26\x94}\x94(\x8c\x05group\x94\x8c\x03SCH\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x05\x14\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-05-20_plate_mapping_file28.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06CAGTTG\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate27\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x05\x11\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-05-17_plate_mapping_file26.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?PbM\xd2\xf1\xa9\xfcj\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06GCTACA\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate28\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x05\x11\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-05-17_plate_mapping_file25.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?PbM\xd2\xf1\xa9\xfcj\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06ATCGAT\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate29\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x05\x1c\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-05-28_plate_mapping_file30.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06TGACGC\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate30\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x05\x1c\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-05-28_plate_mapping_file29.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06CAGTTG\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate31\x94}\x94(\x8c\x05group\x94\x8c\x03SCH\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x05\x1e\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-05-30_plate_mapping_file31.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06GCTACA\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate32\x94}\x94(\x8c\x05group\x94\x8c\x03SCH\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x05\x1e\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-05-30_plate_mapping_file32.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\x08barcodes\x94]\x94\x8c\x10CCAATCCCAGCCTTTA\x94as\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06ATCGAT\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate33\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x06\x04\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-06-04_plate_mapping_file34.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06TGACGC\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate34\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x06\x04\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-06-04_plate_mapping_file33.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06CAGTTG\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate35\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x06\x04\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-07-02_plate_mapping_file36.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06ATCGAT\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate36\x94}\x94(\x8c\x05group\x94\x8c\x03SCH\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x05\x1e\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-07-02_plate_mapping_file35.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06TGACGC\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate37\x94}\x94(\x8c\x05group\x94\x8c\x11MA22VaccineCohort\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\t\x18\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-09-24_plate_mapping_file37.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06ATCGAT\x94\x8c\x12upstream2_mismatch\x94K\x01uuj\xf3\x01\x00\x00}\x94(j\x00\x01\x00\x00j\x01\x01\x00\x00j\x02\x01\x00\x00j}\x02\x00\x00C\x04\x07\xe8\t\x18\x94\x85\x94R\x94j\x04\x01\x00\x00j\x05\x01\x00\x00j\x06\x01\x00\x00j\x07\x01\x00\x00j\x08\x01\x00\x00j\t\x01\x00\x00j\n\x01\x00\x00}\x94j\x0c\x01\x00\x00}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06uj\x1e\x01\x00\x00}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00uj&\x01\x00\x00}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00uj1\x01\x00\x00}\x94(j;\x01\x00\x00j<\x01\x00\x00j=\x01\x00\x00K\x01uu\x8c\x07plate39\x94}\x94(\x8c\x05group\x94\x8c\nPooledSera\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\t\x19\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-09-25_plate_mapping_file40.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06GCTACA\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate40\x94}\x94(\x8c\x05group\x94\x8c\x11MA22VaccineCohort\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\t\x19\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-09-25_plate_mapping_file41.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\x05wells\x94]\x94(\x8c\x03C10\x94\x8c\x03C11\x94es\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06GCTACA\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate41\x94}\x94(\x8c\x05group\x94\x8c\x11MA22VaccineCohort\x94\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\t\x19\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-09-25_plate_mapping_file39.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(j\x0e\x01\x00\x00M\xf4\x01j\x0f\x01\x00\x00G?tz\xe1G\xae\x14{j\x10\x01\x00\x00}\x94(j\x12\x01\x00\x00G?\x1a6\xe2\xeb\x1cC-j\x13\x01\x00\x00K\x04j\x14\x01\x00\x00K\x02uj\x15\x01\x00\x00}\x94(j\x17\x01\x00\x00G?tz\xe1G\xae\x14{j\x18\x01\x00\x00K\x04j\x19\x01\x00\x00K\x02uj\x1a\x01\x00\x00M\xe8\x03j\x1b\x01\x00\x00Kdj\x1c\x01\x00\x00K\x03j\x1d\x01\x00\x00K\x06u\x8c\x0fcurvefit_params\x94}\x94(j \x01\x00\x00K\x01j!\x01\x00\x00jc\x02\x00\x00j#\x01\x00\x00K\x00j$\x01\x00\x00jd\x02\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(j(\x01\x00\x00G\x00\x00\x00\x00\x00\x00\x00\x00j)\x01\x00\x00}\x94(j+\x01\x00\x00G?\xe0\x00\x00\x00\x00\x00\x00j,\x01\x00\x00G?\xc3333333uj-\x01\x00\x00jh\x02\x00\x00j/\x01\x00\x00ji\x02\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06ATCGAT\x94\x8c\x12upstream2_mismatch\x94K\x01uuu\x8c\x14miscellaneous_plates\x94}\x94(\x8c\x13240111_initial_H3N2\x94}\x94(\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x01\x0b\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c=data/miscellaneous_plates/H3N2library_initialPool_samples.csv\x94u\x8c\x12240124_repool_H3N2\x94}\x94(\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x01\x18\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8cGdata/miscellaneous_plates/2024-01-22_H3N2_sampleData_rePool_MOItest.csv\x94u\x8c\x12240207_repool_H3N2\x94}\x94(\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x02\x07\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8cGdata/miscellaneous_plates/2024-02-07_H3N2_sampleData_rePool_MOItest.csv\x94u\x8c\x12240207_repool_H1N1\x94}\x94(\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x02\x07\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH1N1_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8cGdata/miscellaneous_plates/2024-02-07_H1N1_sampleData_rePool_MOItest.csv\x94u\x8c\x1f240328_repool_H3N2_variableCell\x94}\x94(\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\x03\x1c\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8cBdata/miscellaneous_plates/2024-03-28_H3N2_MOItest_variableCell.csv\x94u\x8c\x1c240924_repool_H3N2_balancing\x94}\x94(\x8c\x04date\x94j}\x02\x00\x00C\x04\x07\xe8\t\x18\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c>data/miscellaneous_plates/2024-09-24_repool_H3N2_balancing.csv\x94\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06GCTACA\x94\x8c\x12upstream2_mismatch\x94K\x01uuuu\x8c\x04rule\x94\x8c\rprocess_plate\x94\x8c\x0fbench_iteration\x94N\x8c\tscriptdir\x94\x8ck/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/seqneut-pipeline/notebooks\x94ub.'); from snakemake.logging import logger; logger.printshellcmds = False; import os; os.chdir(r'/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024');
######## snakemake preamble end #########

Process plate counts to get fraction infectivities and fit curves¶

This notebook is designed to be run using snakemake, and analyzes a plate of sequencing-based neutralization assays.

The plots generated by this notebook are interactive, so you can mouseover points for details, use the mouse-scroll to zoom and pan, and use interactive dropdowns at the bottom of the plots.

Setup¶

Import Python modules:

In [2]:
import pickle
import sys

import altair as alt

import matplotlib.pyplot as plt

import neutcurve

import numpy

import pandas as pd

import ruamel.yaml as yaml

_ = alt.data_transformers.disable_max_rows()

Get the variables passed by snakemake:

In [3]:
count_csvs = snakemake.input.count_csvs
fate_csvs = snakemake.input.fate_csvs
viral_library_csv = snakemake.input.viral_library_csv
neut_standard_set_csv = snakemake.input.neut_standard_set_csv
qc_drops_yaml = snakemake.output.qc_drops
frac_infectivity_csv = snakemake.output.frac_infectivity_csv
fits_csv = snakemake.output.fits_csv
fits_pickle = snakemake.output.fits_pickle
samples = snakemake.params.samples
plate = snakemake.wildcards.plate
plate_params = snakemake.params.plate_params

# get thresholds turning lists into tuples as needed
manual_drops = {
    filter_type: [tuple(w) if isinstance(w, list) else w for w in filter_drops]
    for (filter_type, filter_drops) in plate_params["manual_drops"].items()
}
group = plate_params["group"]
qc_thresholds = plate_params["qc_thresholds"]
curvefit_params = plate_params["curvefit_params"]
curvefit_qc = plate_params["curvefit_qc"]
curvefit_qc["barcode_serum_replicates_ignore_curvefit_qc"] = [
    tuple(w) for w in curvefit_qc["barcode_serum_replicates_ignore_curvefit_qc"]
]

print(f"Processing {plate=}")

samples_df = pd.DataFrame(plate_params["samples"])
print(f"\nPlate has {len(samples)} samples (wells)")
assert all(
    (len(samples_df) == samples_df[c].nunique())
    for c in ["well", "sample", "sample_noplate"]
)
assert len(samples_df) == len(
    samples_df.groupby(["serum_replicate", "dilution_factor"])
)
assert len(samples) == len(count_csvs) == len(fate_csvs) == len(samples_df)

for d, key, title in [
    (manual_drops, "manual_drops", "Data manually specified to drop:"),
    (qc_thresholds, "qc_thresholds", "QC thresholds applied to data:"),
    (curvefit_params, "curvefit_params", "Curve-fitting parameters:"),
    (curvefit_qc, "curvefit_qc", "Curve-fitting QC:"),
]:
    print(f"\n{title}")
    yaml.YAML(typ="rt").dump({key: d}, stream=sys.stdout)
Processing plate='plate38'

Plate has 52 samples (wells)

Data manually specified to drop:
manual_drops: {}
QC thresholds applied to data:
qc_thresholds:
  avg_barcode_counts_per_well: 500
  min_neut_standard_frac_per_well: 0.005
  no_serum_per_viral_barcode_filters:
    min_frac: 0.0001
    max_fold_change: 4
    max_wells: 2
  per_neut_standard_barcode_filters:
    min_frac: 0.005
    max_fold_change: 4
    max_wells: 2
  min_neut_standard_count_per_well: 1000
  min_no_serum_count_per_viral_barcode_well: 100
  max_frac_infectivity_per_viral_barcode_well: 3
  min_dilutions_per_barcode_serum_replicate: 6
Curve-fitting parameters:
curvefit_params:
  frac_infectivity_ceiling: 1
  fixtop:
  - 0.6
  - 1
  fixbottom: 0
  fixslope:
  - 0.8
  - 10
Curve-fitting QC:
curvefit_qc:
  max_frac_infectivity_at_least: 0.0
  goodness_of_fit:
    min_R2: 0.5
    max_RMSD: 0.15
  serum_replicates_ignore_curvefit_qc: []
  barcode_serum_replicates_ignore_curvefit_qc: []

Set up dictionary to keep track of wells, barcodes, well-barcodes, and serum-replicates that are dropped:

In [4]:
qc_drops = {
    "wells": {},
    "barcodes": {},
    "barcode_wells": {},
    "barcode_serum_replicates": {},
    "serum_replicates": {},
}

assert set(manual_drops).issubset(
    qc_drops
), f"{manual_drops.keys()=}, {qc_drops.keys()}"

Statistics on barcode-parsing for each sample¶

Make interactive chart of the "fates" of the sequencing reads parsed for each sample on the plate.

If most sequencing reads are not "valid barcodes", this could potentially indicate some problem in the sequencing or barcode set you are parsing.

Potential fates are:

  • valid barcode: barcode that matches a known virus or neutralization standard, we hope most reads are this.
  • invalid barcode: a barcode with proper flanking sequences, but does not match a known virus or neutralization standard. If you have a lot of reads of this type, it is probably a good idea to look at the invalid barcode CSVs (in the ./results/barcode_invalid/ subdirectory created by the pipeline) to see what these invalid barcodes are.
  • unparseable barcode: could not parse a barcode from this read as there was not a sequence of the correct length with the appropriate flanking sequence.
  • invalid outer flank: if using an outer upstream or downstream region (upstream2 or downstream2 for the illuminabarcodeparser), reads that are otherwise valid except for this outer flank. Typically you would be using upstream2 if you have a plate index embedded in your primer, and reads with this classification correspond to a different index than the one for this plate.
  • low quality barcode: low-quality or N nucleotides in barcode, could indicate problem with sequencing.
  • failed chastity filter: reads that failed the Illumina chastity filter, if these are reported in the FASTQ (they may not be).

Also, if the number of reads per sample is very uneven, that could indicate that you did not do a good job of balancing the different samples in the Illumina sequencing.

In [5]:
fates = (
    pd.concat([pd.read_csv(f).assign(sample=s) for f, s in zip(fate_csvs, samples)])
    .merge(samples_df, validate="many_to_one", on="sample")
    .assign(
        fate_counts=lambda x: x.groupby("fate")["count"].transform("sum"),
        sample_well=lambda x: x["sample_noplate"] + " (" + x["well"] + ")",
    )
    .query("fate_counts > 0")[  # only keep fates with at least one count
        ["fate", "count", "well", "serum_replicate", "sample_well", "dilution_factor"]
    ]
)

assert len(fates) == len(fates.drop_duplicates())

serum_replicates = sorted(fates["serum_replicate"].unique())
sample_wells = list(
    fates.sort_values(["serum_replicate", "dilution_factor"])["sample_well"]
)


serum_selection = alt.selection_point(
    fields=["serum_replicate"],
    bind=alt.binding_select(
        options=[None] + serum_replicates,
        labels=["all"] + serum_replicates,
        name="serum",
    ),
)

fates_chart = (
    alt.Chart(fates)
    .add_params(serum_selection)
    .transform_filter(serum_selection)
    .encode(
        alt.X("count", scale=alt.Scale(nice=False, padding=3)),
        alt.Y(
            "sample_well",
            title=None,
            sort=sample_wells,
        ),
        alt.Color("fate", sort=sorted(fates["fate"].unique(), reverse=True)),
        alt.Order("fate", sort="descending"),
        tooltip=fates.columns.tolist(),
    )
    .mark_bar(height={"band": 0.85})
    .properties(
        height=alt.Step(10),
        width=200,
        title=f"Barcode parsing for {plate}",
    )
    .configure_axis(grid=False)
)

fates_chart
Out[5]:

Read barcode counts and apply manually specified drops¶

Read the counts per barcode:

In [6]:
# get barcode counts
counts = (
    pd.concat([pd.read_csv(c).assign(sample=s) for c, s in zip(count_csvs, samples)])
    .merge(samples_df, validate="many_to_one", on="sample")
    .drop(columns=["replicate", "plate", "fastq"])
    .assign(sample_well=lambda x: x["sample_noplate"] + " (" + x["well"] + ")")
)

# classify barcodes as viral or neut standard
barcode_class = pd.concat(
    [
        pd.read_csv(viral_library_csv)[["barcode", "strain"]].assign(
            neut_standard=False,
        ),
        pd.read_csv(neut_standard_set_csv)[["barcode"]].assign(
            neut_standard=True,
            strain=pd.NA,
        ),
    ],
    ignore_index=True,
)

# merge counts and classification of barcodes
assert set(counts["barcode"]) == set(barcode_class["barcode"])
counts = counts.merge(barcode_class, on="barcode", validate="many_to_one")
assert set(sample_wells) == set(counts["sample_well"])
assert set(serum_replicates) == set(counts["serum_replicate"])

Apply any manually specified data drops:

In [7]:
for filter_type, filter_drops in manual_drops.items():
    print(f"\nDropping {len(filter_drops)} {filter_type} specified in manual_drops")
    assert filter_type in qc_drops
    qc_drops[filter_type].update(
        {w: "manual_drop" for w in filter_drops if not isinstance(w, list)}
    )
    if filter_type == "barcode_wells":
        counts = counts[
            ~counts.assign(
                barcode_well=lambda x: x.apply(
                    lambda r: (r["barcode"], r["well"]), axis=1
                )
            )["barcode_well"].isin(qc_drops[filter_type])
        ]
    elif filter_type == "barcode_serum_replicates":
        counts = counts[
            ~counts.assign(
                barcode_serum_replicate=lambda x: x.apply(
                    lambda r: (r["barcode"], r["serum_replicate"]), axis=1
                )
            )["barcode_serum_replicate"].isin(qc_drops[filter_type])
        ]
    elif filter_type == "wells":
        counts = counts[~counts["well"].isin(qc_drops[filter_type])]
    elif filter_type == "barcodes":
        counts = counts[~counts["barcode"].isin(qc_drops[filter_type])]
    else:
        assert filter_type in set(counts.columns)
        counts = counts[~counts[filter_type].isin(qc_drops[filter_type])]

Average counts per barcode in each well¶

Plot average counts per barcode. If a sample has inadequate barcode counts, it may not have good enough statistics for accurate analysis, and a QC-threshold is applied:

In [8]:
avg_barcode_counts = (
    counts.groupby(
        ["well", "serum_replicate", "sample_well"],
        dropna=False,
        as_index=False,
    )
    .aggregate(avg_count=pd.NamedAgg("count", "mean"))
    .assign(
        fails_qc=lambda x: (
            x["avg_count"] < qc_thresholds["avg_barcode_counts_per_well"]
        ),
    )
)

avg_barcode_counts_chart = (
    alt.Chart(avg_barcode_counts)
    .add_params(serum_selection)
    .transform_filter(serum_selection)
    .encode(
        alt.X(
            "avg_count",
            title="average barcode counts per well",
            scale=alt.Scale(nice=False, padding=3),
        ),
        alt.Y("sample_well", sort=sample_wells),
        alt.Color(
            "fails_qc",
            title=f"fails {qc_thresholds['avg_barcode_counts_per_well']=}",
            legend=alt.Legend(titleLimit=500),
        ),
        tooltip=[
            alt.Tooltip(c, format=".3g") if avg_barcode_counts[c].dtype == float else c
            for c in avg_barcode_counts.columns
        ],
    )
    .mark_bar(height={"band": 0.85})
    .properties(
        height=alt.Step(10),
        width=250,
        title=f"Average barcode counts per well for {plate}",
    )
    .configure_axis(grid=False)
)

display(avg_barcode_counts_chart)

# drop wells failing QC
avg_barcode_counts_per_well_drops = list(avg_barcode_counts.query("fails_qc")["well"])
print(
    f"\nDropping {len(avg_barcode_counts_per_well_drops)} wells for failing "
    f"{qc_thresholds['avg_barcode_counts_per_well']=}: "
    + str(avg_barcode_counts_per_well_drops)
)
qc_drops["wells"].update(
    {w: "avg_barcode_counts_per_well" for w in avg_barcode_counts_per_well_drops}
)
counts = counts[~counts["well"].isin(qc_drops["wells"])]
Dropping 0 wells for failing qc_thresholds['avg_barcode_counts_per_well']=500: []

Fraction of counts from neutralization standard¶

Determine the fraction of counts from the neutralization standard in each sample, and make sure this fraction passess the QC threshold.

In [9]:
neut_standard_fracs = (
    counts.assign(
        neut_standard_count=lambda x: x["count"] * x["neut_standard"].astype(int)
    )
    .groupby(
        ["well", "serum_replicate", "sample_well"],
        dropna=False,
        as_index=False,
    )
    .aggregate(
        total_count=pd.NamedAgg("count", "sum"),
        neut_standard_count=pd.NamedAgg("neut_standard_count", "sum"),
    )
    .assign(
        neut_standard_frac=lambda x: x["neut_standard_count"] / x["total_count"],
        fails_qc=lambda x: (
            x["neut_standard_frac"] < qc_thresholds["min_neut_standard_frac_per_well"]
        ),
    )
)

neut_standard_fracs_chart = (
    alt.Chart(neut_standard_fracs)
    .add_params(serum_selection)
    .transform_filter(serum_selection)
    .encode(
        alt.X(
            "neut_standard_frac",
            title="frac counts from neutralization standard per well",
            scale=alt.Scale(nice=False, padding=3),
        ),
        alt.Y("sample_well", sort=sample_wells),
        alt.Color(
            "fails_qc",
            title=f"fails {qc_thresholds['min_neut_standard_frac_per_well']=}",
            legend=alt.Legend(titleLimit=500),
        ),
        tooltip=[
            alt.Tooltip(c, format=".3g") if neut_standard_fracs[c].dtype == float else c
            for c in neut_standard_fracs.columns
        ],
    )
    .mark_bar(height={"band": 0.85})
    .properties(
        height=alt.Step(10),
        width=250,
        title=f"Neutralization-standard fracs per well for {plate}",
    )
    .configure_axis(grid=False)
    .configure_legend(titleLimit=1000)
)

display(neut_standard_fracs_chart)

# drop wells failing QC
min_neut_standard_frac_per_well_drops = list(
    neut_standard_fracs.query("fails_qc")["well"]
)
print(
    f"\nDropping {len(min_neut_standard_frac_per_well_drops)} wells for failing "
    f"{qc_thresholds['min_neut_standard_frac_per_well']=}: "
    + str(min_neut_standard_frac_per_well_drops)
)
qc_drops["wells"].update(
    {
        w: "min_neut_standard_frac_per_well"
        for w in min_neut_standard_frac_per_well_drops
    }
)
counts = counts[~counts["well"].isin(qc_drops["wells"])]
Dropping 0 wells for failing qc_thresholds['min_neut_standard_frac_per_well']=0.005: []

Consistency and minimum fractions for barcodes¶

We examine the fraction of counts attributable to each barcode. We do this splitting the data two ways:

  1. Looking at all viral (but not neut-standard) barcodes only for the no-serum samples (wells).

  2. Looking at just the neut-standard barcodes for all samples (wells).

The reasons is that if the experiment is set up perfectly, these fractions should be the same across all samples for each barcode. (We do not expect viral barcodes to have consistent fractions across no-serum samples as they will be neutralized differently depending on strain).

We plot these fractions in interactive plots (you can mouseover points and zoom) so you can identify barcodes that fail the expected consistency QC thresholds.

We also make sure the barcodes meet specified QC minimum thresholds for all samples, and flag any that do not.

In [10]:
barcode_selection = alt.selection_point(fields=["barcode"], on="mouseover", empty=False)

# look at all samples for neut standard barcodes, or no-serum samples for all barcodes
for is_neut_standard, df in counts.groupby("neut_standard"):
    if is_neut_standard:
        print(
            f"\n\n{'=' * 89}\nAnalyzing neut-standard barcodes from all samples (wells)"
        )
        qc_name = "per_neut_standard_barcode_filters"
    else:
        print(f"\n\n{'=' * 89}\nAnalyzing all barcodes from no-serum samples (wells)")
        qc_name = "no_serum_per_viral_barcode_filters"
        df = df.query("serum == 'none'")

    df = df.assign(
        sample_counts=lambda x: x.groupby("sample")["count"].transform("sum"),
        count_frac=lambda x: x["count"] / x["sample_counts"],
        median_count_frac=lambda x: x.groupby("barcode")["count_frac"].transform(
            "median"
        ),
        fold_change_from_median=lambda x: numpy.where(
            x["count_frac"] > x["median_count_frac"],
            x["count_frac"] / x["median_count_frac"],
            x["median_count_frac"] / x["count_frac"],
        ),
    )[
        [
            "barcode",
            "count",
            "well",
            "sample_well",
            "count_frac",
            "median_count_frac",
            "fold_change_from_median",
        ]
        + ([] if is_neut_standard else ["strain"])
    ]

    # barcode fails QC if fails in sufficient wells
    qc = qc_thresholds[qc_name]
    print(f"Apply QC {qc_name}: {qc}\n")
    fails_qc = (
        df.assign(
            fails_qc=lambda x: ~(
                (x["count_frac"] >= qc["min_frac"])
                & (x["fold_change_from_median"] <= qc["max_fold_change"])
            ),
        )
        .groupby("barcode", as_index=False)
        .aggregate(n_wells_fail_qc=pd.NamedAgg("fails_qc", "sum"))
        .assign(fails_qc=lambda x: x["n_wells_fail_qc"] >= qc["max_wells"])[
            ["barcode", "fails_qc"]
        ]
    )
    df = df.merge(fails_qc, on="barcode", validate="many_to_one")

    # make chart
    evenness_chart = (
        alt.Chart(df)
        .add_params(barcode_selection)
        .encode(
            alt.X(
                "count_frac",
                title=(
                    "barcode's fraction of neut standard counts"
                    if is_neut_standard
                    else "barcode's fraction of non-neut standard counts"
                ),
                scale=alt.Scale(nice=False, padding=5),
            ),
            alt.Y("sample_well", sort=sample_wells),
            alt.Fill(
                "fails_qc",
                title=f"fails {qc_name}",
                legend=alt.Legend(titleLimit=500),
            ),
            strokeWidth=alt.condition(barcode_selection, alt.value(2), alt.value(0)),
            size=alt.condition(barcode_selection, alt.value(60), alt.value(35)),
            tooltip=[
                alt.Tooltip(c, format=".2g") if df[c].dtype == float else c
                for c in df.columns
            ],
        )
        .mark_circle(fillOpacity=0.45, stroke="black", strokeOpacity=1)
        .properties(
            height=alt.Step(10),
            width=300,
            title=alt.TitleParams(
                (
                    f"{plate} all samples, neut-standard barcodes"
                    if is_neut_standard
                    else f"{plate} no-serum samples, all barcodes"
                ),
                subtitle="x-axis is zoomable (use mouse scroll/pan)",
            ),
        )
        .configure_axis(grid=False)
        .configure_legend(titleLimit=1000)
        .interactive()
    )

    display(evenness_chart)

    # drop barcodes failing QC
    barcode_drops = list(fails_qc.query("fails_qc")["barcode"])
    print(
        f"\nDropping {len(barcode_drops)} barcodes for failing {qc=}: {barcode_drops}"
    )
    qc_drops["barcodes"].update(
        {bc: "min_neut_standard_frac_per_well" for bc in barcode_drops}
    )
    counts = counts[~counts["barcode"].isin(qc_drops["barcodes"])]

=========================================================================================
Analyzing all barcodes from no-serum samples (wells)
Apply QC no_serum_per_viral_barcode_filters: {'min_frac': 0.0001, 'max_fold_change': 4, 'max_wells': 2}

Dropping 3 barcodes for failing qc={'min_frac': 0.0001, 'max_fold_change': 4, 'max_wells': 2}: ['CGTCCCTGGCGTGTCG', 'TATATGGAATACTAAA', 'TCTCCGATAGCCCTAC']


=========================================================================================
Analyzing neut-standard barcodes from all samples (wells)
Apply QC per_neut_standard_barcode_filters: {'min_frac': 0.005, 'max_fold_change': 4, 'max_wells': 2}

Dropping 0 barcodes for failing qc={'min_frac': 0.005, 'max_fold_change': 4, 'max_wells': 2}: []

Compute fraction infectivity¶

The fraction infectivity for viral barcode $v_b$ in sample $s$ is computed as: $$ F_{v_b,s} = \frac{c_{v_b,s} / \left(\sum_{n_b} c_{n_b,s}\right)}{{\rm median}_{s_0}\left[ c_{v_b,s_0} / \left(\sum_{n_b} c_{n_b,s_0}\right)\right]} $$ where

  • $c_{v_b,s}$ is the counts of viral barcode $v_b$ in sample $s$.
  • $\sum_{n_b} c_{n_b,s}$ is the sum of the counts for all neutralization standard barcodes $n_b$ for sample $s$.
  • $c_{v_b,s_0}$ is the counts of viral barcode $v_b$ in no-serum sample $s_0$.
  • $\sum_{n_b} c_{n_b,s_0}$ is the sum of the counts for all neutralization standard barcodes $n_b$ for no-serum sample $s_0$.
  • ${\rm median}_{s_0}\left[ c_{v_b,s_0} / \left(\sum_{n_b} c_{n_b,s_0}\right)\right]$ is the median taken across all no-serum samples of the counts of viral barcode $v_b$ versus the total counts for all neutralization standard barcodes.

First, compute the total neutralization-standard counts for each sample (well). Plot these, and drop any wells that do not meet the QC threshold.

In [11]:
neut_standard_counts = (
    counts.query("neut_standard")
    .groupby(
        ["well", "serum_replicate", "sample_well", "dilution_factor"],
        dropna=False,
        as_index=False,
    )
    .aggregate(neut_standard_count=pd.NamedAgg("count", "sum"))
    .assign(
        fails_qc=lambda x: (
            x["neut_standard_count"] < qc_thresholds["min_neut_standard_count_per_well"]
        ),
    )
)

neut_standard_counts_chart = (
    alt.Chart(neut_standard_counts)
    .add_params(serum_selection)
    .transform_filter(serum_selection)
    .encode(
        alt.X(
            "neut_standard_count",
            title="counts from neutralization standard",
            scale=alt.Scale(nice=False, padding=3),
        ),
        alt.Y("sample_well", sort=sample_wells),
        alt.Color(
            "fails_qc",
            title=f"fails {qc_thresholds['min_neut_standard_count_per_well']=}",
            legend=alt.Legend(titleLimit=500),
        ),
        tooltip=[
            (
                alt.Tooltip(c, format=".3g")
                if neut_standard_counts[c].dtype == float
                else c
            )
            for c in neut_standard_counts.columns
        ],
    )
    .mark_bar(height={"band": 0.85})
    .properties(
        height=alt.Step(10),
        width=250,
        title=f"Neutralization-standard counts for {plate}",
    )
    .configure_axis(grid=False)
    .configure_legend(titleLimit=1000)
)

display(neut_standard_counts_chart)

# drop wells failing QC
min_neut_standard_count_per_well_drops = list(
    neut_standard_counts.query("fails_qc")["well"]
)
print(
    f"\nDropping {len(min_neut_standard_count_per_well_drops)} wells for failing "
    f"{qc_thresholds['min_neut_standard_count_per_well']=}: "
    + str(min_neut_standard_count_per_well_drops)
)
qc_drops["wells"].update(
    {
        w: "min_neut_standard_count_per_well"
        for w in min_neut_standard_count_per_well_drops
    }
)
neut_standard_counts = neut_standard_counts[
    ~neut_standard_counts["well"].isin(qc_drops["wells"])
]
counts = counts[~counts["well"].isin(qc_drops["wells"])]
Dropping 0 wells for failing qc_thresholds['min_neut_standard_count_per_well']=1000: []

Compute and plot the no-serum sample viral barcode counts and check if they pass the QC filters.

In [12]:
no_serum_counts = (
    counts.query("serum == 'none'")
    .query("not neut_standard")
    .merge(neut_standard_counts, validate="many_to_one")[
        ["barcode", "strain", "well", "sample_well", "count", "neut_standard_count"]
    ]
    .assign(
        fails_qc=lambda x: (
            x["count"] <= qc_thresholds["min_no_serum_count_per_viral_barcode_well"]
        ),
    )
)

strains = sorted(no_serum_counts["strain"].unique())
strain_selection_dropdown = alt.selection_point(
    fields=["strain"],
    bind=alt.binding_select(
        options=[None] + strains,
        labels=["all"] + strains,
        name="virus strain",
    ),
)

# make chart
no_serum_counts_chart = (
    alt.Chart(no_serum_counts)
    .add_params(barcode_selection, strain_selection_dropdown)
    .transform_filter(strain_selection_dropdown)
    .encode(
        alt.X(
            "count", title="viral barcode count", scale=alt.Scale(nice=False, padding=5)
        ),
        alt.Y("sample_well", sort=sample_wells),
        alt.Fill(
            "fails_qc",
            title=f"fails {qc_thresholds['min_no_serum_count_per_viral_barcode_well']=}",
            legend=alt.Legend(titleLimit=500),
        ),
        strokeWidth=alt.condition(barcode_selection, alt.value(2), alt.value(0)),
        size=alt.condition(barcode_selection, alt.value(60), alt.value(35)),
        tooltip=no_serum_counts.columns.tolist(),
    )
    .mark_circle(fillOpacity=0.6, stroke="black", strokeOpacity=1)
    .properties(
        height=alt.Step(10),
        width=400,
        title=f"{plate} viral barcode counts in no-serum samples",
    )
    .configure_axis(grid=False)
    .configure_legend(titleLimit=1000)
    .interactive()
)

display(no_serum_counts_chart)

# drop barcode / wells failing QC
min_no_serum_count_per_viral_barcode_well_drops = list(
    no_serum_counts.query("fails_qc")[["barcode", "well"]].itertuples(
        index=False, name=None
    )
)
print(
    f"\nDropping {len(min_no_serum_count_per_viral_barcode_well_drops)} barcode-wells for failing "
    f"{qc_thresholds['min_no_serum_count_per_viral_barcode_well']=}: "
    + str(min_no_serum_count_per_viral_barcode_well_drops)
)
qc_drops["barcode_wells"].update(
    {
        w: "min_no_serum_count_per_viral_barcode_well"
        for w in min_no_serum_count_per_viral_barcode_well_drops
    }
)
no_serum_counts = no_serum_counts[
    ~no_serum_counts.assign(
        barcode_well=lambda x: x.apply(lambda r: (r["barcode"], r["well"]), axis=1)
    )["barcode_well"].isin(qc_drops["barcode_wells"])
]
counts = counts[
    ~counts.assign(
        barcode_well=lambda x: x.apply(lambda r: (r["barcode"], r["well"]), axis=1)
    )["barcode_well"].isin(qc_drops["barcode_wells"])
]
Dropping 0 barcode-wells for failing qc_thresholds['min_no_serum_count_per_viral_barcode_well']=100: []

Compute and plot the median ratio of viral barcode count to neut standard counts across no-serum samples. If library composition is equal, all of these values should be similar:

In [13]:
median_no_serum_ratio = (
    no_serum_counts.assign(ratio=lambda x: x["count"] / x["neut_standard_count"])
    .groupby(["barcode", "strain"], as_index=False)
    .aggregate(median_no_serum_ratio=pd.NamedAgg("ratio", "median"))
)

strain_selection = alt.selection_point(fields=["strain"], on="mouseover", empty=False)

median_no_serum_ratio_chart = (
    alt.Chart(median_no_serum_ratio)
    .add_params(strain_selection)
    .encode(
        alt.X(
            "median_no_serum_ratio",
            title="median ratio of counts",
            scale=alt.Scale(nice=False, padding=5),
        ),
        alt.Y(
            "barcode",
            sort=alt.SortField("median_no_serum_ratio", order="descending"),
            axis=alt.Axis(labelFontSize=5),
        ),
        color=alt.condition(strain_selection, alt.value("orange"), alt.value("gray")),
        tooltip=[
            (
                alt.Tooltip(c, format=".3g")
                if median_no_serum_ratio[c].dtype == float
                else c
            )
            for c in median_no_serum_ratio.columns
        ],
    )
    .mark_bar(height={"band": 0.85})
    .properties(
        height=alt.Step(5),
        width=250,
        title=f"{plate} no-serum median ratio viral barcode to neut-standard barcode",
    )
    .configure_axis(grid=False)
    .configure_legend(titleLimit=1000)
)

display(median_no_serum_ratio_chart)

Compute the actual fraction infectivities. We compute both the raw fraction infectivities and the ones with the ceiling applied:

In [14]:
frac_infectivity = (
    counts.query("not neut_standard")
    .query("serum != 'none'")
    .merge(median_no_serum_ratio, validate="many_to_one")
    .merge(neut_standard_counts, validate="many_to_one")
    .assign(
        frac_infectivity_raw=lambda x: (
            (x["count"] / x["neut_standard_count"]) / x["median_no_serum_ratio"]
        ),
        frac_infectivity_ceiling=lambda x: x["frac_infectivity_raw"].clip(
            upper=curvefit_params["frac_infectivity_ceiling"]
        ),
        concentration=lambda x: 1 / x["dilution_factor"],
        plate_barcode=lambda x: x["plate_replicate"] + "-" + x["barcode"],
    )[
        [
            "barcode",
            "plate_barcode",
            "well",
            "strain",
            "serum",
            "serum_replicate",
            "dilution_factor",
            "concentration",
            "frac_infectivity_raw",
            "frac_infectivity_ceiling",
        ]
    ]
)

assert len(
    frac_infectivity.groupby(["serum", "plate_barcode", "dilution_factor"])
) == len(frac_infectivity)
assert frac_infectivity["dilution_factor"].notnull().all()
assert frac_infectivity["frac_infectivity_raw"].notnull().all()
assert frac_infectivity["frac_infectivity_ceiling"].notnull().all()

Plot the fraction infectivities, both the raw values and with the ceiling applied:

In [15]:
frac_infectivity_chart_df = (
    frac_infectivity.assign(
        fails_qc=lambda x: (
            x["frac_infectivity_raw"]
            > qc_thresholds["max_frac_infectivity_per_viral_barcode_well"]
        ),
    )
    .melt(
        id_vars=[
            "barcode",
            "strain",
            "well",
            "serum_replicate",
            "dilution_factor",
            "fails_qc",
        ],
        value_vars=["frac_infectivity_raw", "frac_infectivity_ceiling"],
        var_name="ceiling_applied",
        value_name="frac_infectivity",
    )
    .assign(
        ceiling_applied=lambda x: x["ceiling_applied"].map(
            {
                "frac_infectivity_raw": "raw fraction infectivity",
                "frac_infectivity_ceiling": f"fraction infectivity with ceiling at {curvefit_params['frac_infectivity_ceiling']}",
            }
        )
    )
)

frac_infectivity_chart = (
    alt.Chart(frac_infectivity_chart_df)
    .add_params(strain_selection_dropdown, barcode_selection)
    .transform_filter(strain_selection_dropdown)
    .encode(
        alt.X(
            "dilution_factor",
            title="dilution factor",
            scale=alt.Scale(nice=False, padding=5, type="log"),
        ),
        alt.Y(
            "frac_infectivity",
            title="fraction infectivity",
            scale=alt.Scale(nice=False, padding=5),
        ),
        alt.Column(
            "ceiling_applied",
            sort="descending",
            title=None,
            header=alt.Header(labelFontSize=13, labelFontStyle="bold", labelPadding=2),
        ),
        alt.Row(
            "serum_replicate",
            title=None,
            spacing=3,
            header=alt.Header(labelFontSize=13, labelFontStyle="bold"),
        ),
        alt.Detail("barcode"),
        alt.Shape(
            "fails_qc",
            title=f"fails {qc_thresholds['max_frac_infectivity_per_viral_barcode_well']=}",
            legend=alt.Legend(titleLimit=500, orient="bottom"),
        ),
        color=alt.condition(
            barcode_selection, alt.value("black"), alt.value("MediumBlue")
        ),
        strokeWidth=alt.condition(barcode_selection, alt.value(3), alt.value(1)),
        opacity=alt.condition(barcode_selection, alt.value(1), alt.value(0.25)),
        tooltip=[
            (
                alt.Tooltip(c, format=".3g")
                if frac_infectivity_chart_df[c].dtype == float
                else c
            )
            for c in frac_infectivity_chart_df.columns
        ],
    )
    .mark_line(point=True)
    .properties(
        height=150,
        width=250,
        title=f"Fraction infectivities for {plate}",
    )
    .interactive(bind_x=False)
    .configure_axis(grid=False)
    .configure_legend(titleLimit=1000)
    .configure_point(size=50)
    .resolve_scale(x="independent", y="independent")
)

display(frac_infectivity_chart)

# drop barcode / wells failing QC
max_frac_infectivity_per_viral_barcode_well_drops = list(
    frac_infectivity_chart_df.query("fails_qc")[["barcode", "well"]]
    .drop_duplicates()
    .itertuples(index=False, name=None)
)
print(
    f"\nDropping {len(max_frac_infectivity_per_viral_barcode_well_drops)} barcode-wells for failing "
    f"{qc_thresholds['max_frac_infectivity_per_viral_barcode_well']=}: "
    + str(max_frac_infectivity_per_viral_barcode_well_drops)
)
qc_drops["barcode_wells"].update(
    {
        w: "max_frac_infectivity_per_viral_barcode_well"
        for w in max_frac_infectivity_per_viral_barcode_well_drops
    }
)
frac_infectivity = frac_infectivity[
    ~frac_infectivity.assign(
        barcode_well=lambda x: x.apply(lambda r: (r["barcode"], r["well"]), axis=1)
    )["barcode_well"].isin(qc_drops["barcode_wells"])
]
Dropping 4 barcode-wells for failing qc_thresholds['max_frac_infectivity_per_viral_barcode_well']=3: [('AATGACAGCTGTCTAG', 'B8'), ('GCCGTAGCGAAATCTT', 'B9'), ('AATGACAGCTGTCTAG', 'B9'), ('AGGGACTTTATTGTCC', 'C9')]

Check how many dilutions we have per barcode / serum-replicate:

In [16]:
n_dilutions = (
    frac_infectivity.groupby(["serum_replicate", "strain", "barcode"], as_index=False)
    .aggregate(**{"number of dilutions": pd.NamedAgg("dilution_factor", "nunique")})
    .assign(
        fails_qc=lambda x: (
            x["number of dilutions"]
            < qc_thresholds["min_dilutions_per_barcode_serum_replicate"]
        ),
    )
)

n_dilutions_chart = (
    alt.Chart(n_dilutions)
    .add_params(barcode_selection)
    .encode(
        alt.X("number of dilutions", scale=alt.Scale(nice=False, padding=4)),
        alt.Y("strain", title=None),
        alt.Column(
            "serum_replicate",
            title=None,
            header=alt.Header(labelFontSize=12, labelFontStyle="bold", labelPadding=0),
        ),
        alt.Fill(
            "fails_qc",
            title=f"fails {qc_thresholds['min_dilutions_per_barcode_serum_replicate']=}",
            legend=alt.Legend(titleLimit=500, orient="bottom"),
        ),
        strokeWidth=alt.condition(barcode_selection, alt.value(2), alt.value(0)),
        size=alt.condition(barcode_selection, alt.value(55), alt.value(35)),
        tooltip=[
            alt.Tooltip(c, format=".3g") if n_dilutions[c].dtype == float else c
            for c in n_dilutions.columns
        ],
    )
    .mark_circle(stroke="black", strokeOpacity=1, fillOpacity=0.45)
    .properties(
        height=alt.Step(10),
        width=120,
        title=alt.TitleParams(
            "number of dilutions for each barcode for each serum-replicate", dy=-2
        ),
    )
)

display(n_dilutions_chart)

# drop barcode / serum-replicates failing QC
min_dilutions_per_barcode_serum_replicate_drops = list(
    n_dilutions.query("fails_qc")[["barcode", "serum_replicate"]].itertuples(
        index=False, name=None
    )
)
print(
    f"\nDropping {len(min_dilutions_per_barcode_serum_replicate_drops)} barcode/serum-replicates for failing "
    f"{qc_thresholds['min_dilutions_per_barcode_serum_replicate']=}: "
    + str(min_dilutions_per_barcode_serum_replicate_drops)
)
qc_drops["barcode_serum_replicates"].update(
    {
        w: "min_dilutions_per_barcode_serum_replicate"
        for w in min_dilutions_per_barcode_serum_replicate_drops
    }
)
frac_infectivity = frac_infectivity[
    ~frac_infectivity.assign(
        barcode_serum_replicate=lambda x: x.apply(
            lambda r: (r["barcode"], r["serum_replicate"]), axis=1
        )
    )["barcode_serum_replicate"].isin(qc_drops["barcode_serum_replicates"])
]
Dropping 0 barcode/serum-replicates for failing qc_thresholds['min_dilutions_per_barcode_serum_replicate']=6: []

Fit neutralization curves without applying QC to curves¶

First fit curves to all serum replicates, then we will apply QC on the curve fits. Note that the fitting is done to the fraction infectivities with the ceiling:

In [17]:
fits_noqc = neutcurve.CurveFits(
    frac_infectivity.rename(
        columns={
            "frac_infectivity_ceiling": "fraction infectivity",
            "concentration": "serum concentration",
        }
    ),
    conc_col="serum concentration",
    fracinf_col="fraction infectivity",
    virus_col="strain",
    serum_col="serum_replicate",
    replicate_col="barcode",
    fixtop=curvefit_params["fixtop"],
    fixbottom=curvefit_params["fixbottom"],
    fixslope=curvefit_params["fixslope"],
)

Determine which fits fail the curve fitting QC, and plot them. Note the plot indicates as failing QC any barcode / serum-replicate that fails, even if we are also specified to ignore the QC for that one (so it will not be removed later):

In [18]:
goodness_of_fit = curvefit_qc["goodness_of_fit"]

fit_params_noqc = (
    frac_infectivity.groupby(["serum_replicate", "barcode"], as_index=False)
    .aggregate(max_frac_infectivity=pd.NamedAgg("frac_infectivity_ceiling", "max"))
    .merge(
        fits_noqc.fitParams(average_only=False, no_average=True)[
            ["serum", "virus", "replicate", "r2", "rmsd"]
        ].rename(columns={"serum": "serum_replicate", "replicate": "barcode"}),
        validate="one_to_one",
    )
    .assign(
        fails_max_frac_infectivity_at_least=lambda x: (
            x["max_frac_infectivity"] < curvefit_qc["max_frac_infectivity_at_least"]
        ),
        fails_goodness_of_fit=lambda x: (
            (x["r2"] < goodness_of_fit["min_R2"])
            & (x["rmsd"] > goodness_of_fit["max_RMSD"])
        ),
        fails_qc=lambda x: (
            x["fails_max_frac_infectivity_at_least"] | x["fails_goodness_of_fit"]
        ),
        ignore_qc=lambda x: x.apply(
            lambda r: (
                (
                    r["serum_replicate"]
                    in curvefit_qc["serum_replicates_ignore_curvefit_qc"]
                )
                or (
                    (r["barcode"], r["serum_replicate"])
                    in curvefit_qc["barcode_serum_replicates_ignore_curvefit_qc"]
                )
            ),
            axis=1,
        ),
    )
)

print(f"Plotting barcode / serum-replicates that fail {curvefit_qc=}\n")

for prop, col in [
    ("max frac infectivity", "max_frac_infectivity"),
    ("curve fit R2", "r2"),
    ("curve fit RMSD", "rmsd"),
]:
    fit_params_noqc_chart = (
        alt.Chart(fit_params_noqc)
        .add_params(barcode_selection)
        .encode(
            alt.X(col, title=prop, scale=alt.Scale(nice=False, padding=4)),
            alt.Y("virus", title=None),
            alt.Fill("fails_qc"),
            alt.Column(
                "serum_replicate",
                title=None,
                header=alt.Header(
                    labelFontSize=12, labelFontStyle="bold", labelPadding=0
                ),
            ),
            strokeWidth=alt.condition(barcode_selection, alt.value(2), alt.value(0)),
            size=alt.condition(barcode_selection, alt.value(55), alt.value(35)),
            tooltip=[
                alt.Tooltip(c, format=".3g") if fit_params_noqc[c].dtype == float else c
                for c in fit_params_noqc.columns
            ],
        )
        .mark_circle(stroke="black", strokeOpacity=1, fillOpacity=0.55)
        .properties(
            height=alt.Step(10),
            width=120,
            title=alt.TitleParams(f"{prop} for each barcode serum-replicate", dy=-2),
        )
    )
    display(fit_params_noqc_chart)
Plotting barcode / serum-replicates that fail curvefit_qc={'max_frac_infectivity_at_least': 0.0, 'goodness_of_fit': {'min_R2': 0.5, 'max_RMSD': 0.15}, 'serum_replicates_ignore_curvefit_qc': [], 'barcode_serum_replicates_ignore_curvefit_qc': []}

Now get all barcode / serum-replicate pairs that fail any of the QC. Plot curves for just these virus / serum-replicates (we plot all barcodes for a virus even if just one fails QC), and then exclude any that are not specified to ignore the QC:

In [19]:
barcode_serum_replicates_fail_qc = fit_params_noqc.query("fails_qc").reset_index(
    drop=True
)
print(f"Here are barcode / serum-replicates that fail {curvefit_qc=}")
display(barcode_serum_replicates_fail_qc)

if len(barcode_serum_replicates_fail_qc):
    print("\nCurves for viruses and serum-replicates with at least one failed barcode:")
    fig, _ = fits_noqc.plotReplicates(
        sera=sorted(barcode_serum_replicates_fail_qc["serum_replicate"].unique()),
        viruses=sorted(barcode_serum_replicates_fail_qc["virus"].unique()),
        attempt_shared_legend=False,
        legendfontsize=8,
        titlesize=10,
        ticksize=10,
        ncol=6,
        draw_in_bounds=True,
    )
    display(fig)
    plt.close(fig)

# drop barcode / serum-replicates failing QC
for qc_filter in ["max_frac_infectivity_at_least", "goodness_of_fit"]:
    fits_qc_drops = list(
        fit_params_noqc.query(f"fails_{qc_filter} and (not ignore_qc)")[
            ["barcode", "serum_replicate"]
        ].itertuples(index=False, name=None)
    )
    print(
        f"\nDropping {len(fits_qc_drops)} barcode/serum-replicates for failing "
        f"{qc_filter}={curvefit_qc[qc_filter]}: " + str(fits_qc_drops)
    )
    qc_drops["barcode_serum_replicates"].update({w: qc_filter for w in fits_qc_drops})
    frac_infectivity = frac_infectivity[
        ~frac_infectivity.assign(
            barcode_serum_replicate=lambda x: x.apply(
                lambda r: (r["barcode"], r["serum_replicate"]), axis=1
            )
        )["barcode_serum_replicate"].isin(qc_drops["barcode_serum_replicates"])
    ]
    fit_params_noqc = fit_params_noqc[
        ~fit_params_noqc.assign(
            barcode_serum_replicate=lambda x: x.apply(
                lambda r: (r["barcode"], r["serum_replicate"]), axis=1
            )
        )["barcode_serum_replicate"].isin(qc_drops["barcode_serum_replicates"])
    ]
Here are barcode / serum-replicates that fail curvefit_qc={'max_frac_infectivity_at_least': 0.0, 'goodness_of_fit': {'min_R2': 0.5, 'max_RMSD': 0.15}, 'serum_replicates_ignore_curvefit_qc': [], 'barcode_serum_replicates_ignore_curvefit_qc': []}
serum_replicate barcode max_frac_infectivity virus r2 rmsd fails_max_frac_infectivity_at_least fails_goodness_of_fit fails_qc ignore_qc
Dropping 0 barcode/serum-replicates for failing max_frac_infectivity_at_least=0.0: []

Dropping 0 barcode/serum-replicates for failing goodness_of_fit={'min_R2': 0.5, 'max_RMSD': 0.15}: []

Fit neutralization curves after applying QC¶

No we re-fit curves after applying all the QC:

In [20]:
fits_qc = neutcurve.CurveFits(
    frac_infectivity.rename(
        columns={
            "frac_infectivity_ceiling": "fraction infectivity",
            "concentration": "serum concentration",
        }
    ),
    conc_col="serum concentration",
    fracinf_col="fraction infectivity",
    virus_col="strain",
    serum_col="serum",
    replicate_col="plate_barcode",
    fixtop=curvefit_params["fixtop"],
    fixbottom=curvefit_params["fixbottom"],
    fixslope=curvefit_params["fixslope"],
)

fit_params_qc = fits_qc.fitParams(average_only=False, no_average=True)
assert len(fit_params_qc) <= len(
    fits_noqc.fitParams(average_only=False, no_average=True)
)

print(f"Assigning fits for this plate to {group}")
fit_params_qc.insert(0, "group", group)
Assigning fits for this plate to PooledSera

Plot all the curves that passed QC:

In [21]:
if fits_qc.sera:
    _ = fits_qc.plotReplicates(
        attempt_shared_legend=False,
        legendfontsize=8,
        titlesize=10,
        ticksize=10,
        ncol=6,
        draw_in_bounds=True,
    )
else:
    print("No sera passed QC.")
No description has been provided for this image

Save results to files¶

In [22]:
print(f"Writing fraction infectivities to {frac_infectivity_csv}")
(
    frac_infectivity[
        [
            "serum",
            "strain",
            "plate_barcode",
            "dilution_factor",
            "frac_infectivity_raw",
            "frac_infectivity_ceiling",
        ]
    ]
    .sort_values(["serum", "plate_barcode", "dilution_factor"])
    .to_csv(frac_infectivity_csv, index=False, float_format="%.4g")
)

print(f"\nWriting fit parameters to {fits_csv}")
(
    fit_params_qc.drop(columns=["nreplicates", "ic50_str"]).to_csv(
        fits_csv, index=False, float_format="%.4g"
    )
)

print(f"\nPickling neutcurve.CurveFits object for these data to {fits_pickle}")
with open(fits_pickle, "wb") as f:
    pickle.dump(fits_qc, f)

print(f"\nWriting QC drops to {qc_drops_yaml}")


def tup_to_str(x):
    return " ".join(x) if isinstance(x, tuple) else x


qc_drops_for_yaml = {
    key: {tup_to_str(key2): val2 for key2, val2 in val.items()}
    for key, val in qc_drops.items()
}
with open(qc_drops_yaml, "w") as f:
    yaml.YAML(typ="rt").dump(qc_drops_for_yaml, f)
print("\nHere are the QC drops:\n***************************")
yaml.YAML(typ="rt").dump(qc_drops_for_yaml, sys.stdout)
Writing fraction infectivities to results/plates/plate38/frac_infectivity.csv

Writing fit parameters to results/plates/plate38/curvefits.csv

Pickling neutcurve.CurveFits object for these data to results/plates/plate38/curvefits.pickle
Writing QC drops to results/plates/plate38/qc_drops.yml

Here are the QC drops:
***************************
wells: {}
barcodes:
  CGTCCCTGGCGTGTCG: min_neut_standard_frac_per_well
  TATATGGAATACTAAA: min_neut_standard_frac_per_well
  TCTCCGATAGCCCTAC: min_neut_standard_frac_per_well
barcode_wells:
  AATGACAGCTGTCTAG B8: max_frac_infectivity_per_viral_barcode_well
  GCCGTAGCGAAATCTT B9: max_frac_infectivity_per_viral_barcode_well
  AATGACAGCTGTCTAG B9: max_frac_infectivity_per_viral_barcode_well
  AGGGACTTTATTGTCC C9: max_frac_infectivity_per_viral_barcode_well
barcode_serum_replicates: {}
serum_replicates: {}